/*
 * JaCoLiB
 * Copyright (C) 2008 Alessandro Serra
 * 
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 * 
 */

package it.gashale.jacolib.connection.auth;

import it.gashale.jacolib.core.JacolibError;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintStream;
import java.net.Socket;
import java.util.Random;

public class Authenticator {
	final static private Random random = new Random();
	
	/*
	 * Authentication functions
	 */
	static public boolean authenticate(Socket socket, String secret_string) throws JacolibError, IOException {
		BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
		PrintStream out=new PrintStream(socket.getOutputStream());
		
		boolean ret=false;
		String type=(String)in.readLine();
		if(type.equals("none")) {
		} else if (type.equals("md5")) {
			String random_string=(String)in.readLine();
			String md5=getMD5(random_string, secret_string);
			out.println(md5);
		} else if (type.equals("plain")) {
			out.println(secret_string);
		}
		String res=(String)in.readLine();
		ret=res.equals("correct");
		return ret;
	}
	static public boolean ask_authetication(Socket socket, String auth_type, String secret_string) throws JacolibError, IOException {
		BufferedReader in=new BufferedReader(new InputStreamReader(socket.getInputStream()));
		PrintStream out=new PrintStream(socket.getOutputStream());
		
		boolean ret=false;
		if(auth_type.equals("none")) {
			out.println("none");
			ret=true;
		} else if (auth_type.equals("md5")) {
			out.println("md5");
			String random_string=generateRandomString();
			out.println(random_string);
			String md5=(String)in.readLine();
			ret=getMD5(random_string, secret_string).equals(md5);	
		} else if (auth_type.equals("plain")) {
			out.println("plain");
			String passwd=(String)in.readLine();
			ret=passwd.equals(secret_string);
		}
		
		
		if(ret) {
			out.println("correct");
		} else {
			out.println("incorrect");
		}
		return ret;
	}
	
	static private char[] codes = {
        'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o',
        'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'y', 'z',
        'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
        'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'Y', 'Z',
        '~', ';', '+', '=', '(', ')', '-', '/', '*', '!', ',', '.', '@', '#', '$', '%', '^', '&', 
        '1', '2', '3', '4', '5', '6', '7', '8', '9', '0'
	};
	static public String generateRandomString() {
		StringBuffer ret = new StringBuffer(16);
		for (int i=0; i<16; i++) {
			ret.append(codes[Math.abs(random.nextInt()) % codes.length]);
		}
		return ret.toString();
	}
	static public String getMD5(String random_string, String secret_string) {
		MD5 md5_algo=new MD5();
		String combined = secret_string + random_string;
		int len = combined.length();
		md5_algo.update(combined.getBytes(), len);
		byte sig[] = new byte[16];
		md5_algo.md5final(sig);
		String s=MD5.dumpBytes(sig);
		return s;
	}
}
